Subversion Repositories HelenOS

Rev

Rev 2843 | Rev 2845 | 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. static void fat_sync_node(fat_node_t *node)
  147. {
  148.     /* TODO */
  149. }
  150.  
  151. /** Instantiate a FAT in-core node.
  152.  *
  153.  * FAT stores the info necessary for instantiation of a node in the parent of
  154.  * that node.  This design necessitated the addition of the parent node index
  155.  * parameter to this otherwise generic libfs API.
  156.  */
  157. static void *
  158. fat_node_get(dev_handle_t dev_handle, fs_index_t index, fs_index_t pindex)
  159. {
  160.     link_t *lnk;
  161.     fat_node_t *node = NULL;
  162.     block_t *b;
  163.     unsigned bps;
  164.     unsigned dps;
  165.     fat_dentry_t *d;
  166.     unsigned i, j;
  167.  
  168.     unsigned long key[] = {
  169.         [FIN_KEY_DEV_HANDLE] = dev_handle,
  170.         [FIN_KEY_INDEX] = index
  171.     };
  172.  
  173.     lnk = hash_table_find(&fin_hash, key);
  174.     if (lnk) {
  175.         /*
  176.          * The in-core node was found in the hash table.
  177.          */
  178.         node = hash_table_get_instance(lnk, fat_node_t, fin_link);
  179.         if (!node->refcnt++)
  180.             list_remove(&node->ffn_link);
  181.         return (void *) node;  
  182.     }
  183.  
  184.     bps = fat_bps_get(dev_handle);
  185.     dps = bps / sizeof(fat_dentry_t);
  186.    
  187.     if (!list_empty(&ffn_head)) {
  188.         /*
  189.          * We are going to reuse a node from the free list.
  190.          */
  191.         lnk = ffn_head.next;
  192.         list_remove(lnk);
  193.         node = list_get_instance(lnk, fat_node_t, ffn_link);
  194.         assert(!node->refcnt);
  195.         if (node->dirty)
  196.             fat_sync_node(node);
  197.         key[FIN_KEY_DEV_HANDLE] = node->dev_handle;
  198.         key[FIN_KEY_INDEX] = node->index;
  199.         hash_table_remove(&fin_hash, key, sizeof(key)/sizeof(*key));
  200.     } else {
  201.         /*
  202.          * We need to allocate a new node.
  203.          */
  204.         node = malloc(sizeof(fat_node_t));
  205.         if (!node)
  206.             return NULL;
  207.     }
  208.     fat_node_initialize(node);
  209.     node->refcnt++;
  210.     node->lnkcnt++;
  211.     node->dev_handle = dev_handle;
  212.     node->index = index;
  213.     node->pindex = pindex;
  214.  
  215.     /*
  216.      * Because of the design of the FAT file system, we have no clue about
  217.      * how big (i.e. how many directory entries it contains) is the parent
  218.      * of the node we are trying to instantiate.  However, we know that it
  219.      * must contain a directory entry for our node of interest.  We simply
  220.      * scan the parent until we find it.
  221.      */
  222.     for (i = 0; ; i++) {
  223.         b = fat_block_get(node->dev_handle, node->pindex, i);
  224.         if (!b) {
  225.             node->refcnt--;
  226.             list_append(&node->ffn_link, &ffn_head);
  227.             return NULL;
  228.         }
  229.         for (j = 0; j < dps; j++) {
  230.             d = ((fat_dentry_t *)b->data) + j;
  231.             if (d->firstc == node->index)
  232.                 goto found;
  233.         }
  234.         block_put(b);
  235.     }
  236.    
  237. found:
  238.     if (!(d->attr & (FAT_ATTR_SUBDIR | FAT_ATTR_VOLLABEL)))
  239.         node->type = FAT_FILE;
  240.     if ((d->attr & FAT_ATTR_SUBDIR) || !index)
  241.         node->type = FAT_DIRECTORY;
  242.     assert((node->type == FAT_FILE) || (node->type == FAT_DIRECTORY));
  243.    
  244.     node->size = uint32_t_le2host(d->size);
  245.     block_put(b);
  246.    
  247.     key[FIN_KEY_DEV_HANDLE] = node->dev_handle;
  248.     key[FIN_KEY_INDEX] = node->index;
  249.     hash_table_insert(&fin_hash, key, &node->fin_link);
  250.  
  251.     return node;
  252. }
  253.  
  254. static void *fat_match(void *prnt, const char *component)
  255. {
  256.     fat_node_t *parentp = (fat_node_t *)prnt;
  257.     char name[FAT_NAME_LEN + 1 + FAT_EXT_LEN + 1];
  258.     unsigned i, j;
  259.     unsigned bps;       /* bytes per sector */
  260.     unsigned dps;       /* dentries per sector */
  261.     unsigned blocks;
  262.     fat_dentry_t *d;
  263.     block_t *b;
  264.  
  265.     bps = fat_bps_get(parentp->dev_handle);
  266.     dps = bps / sizeof(fat_dentry_t);
  267.     blocks = parentp->size / bps + (parentp->size % bps != 0);
  268.     for (i = 0; i < blocks; i++) {
  269.         unsigned dentries;
  270.        
  271.         b = fat_block_get(parentp->dev_handle, parentp->index, i);
  272.         if (!b)
  273.             return NULL;
  274.  
  275.         dentries = (i == blocks - 1) ?
  276.             parentp->size % sizeof(fat_dentry_t) :
  277.             dps;
  278.         for (j = 0; j < dentries; j++) {
  279.             d = ((fat_dentry_t *)b->data) + j;
  280.             if (d->attr & FAT_ATTR_VOLLABEL) {
  281.                 /* volume label entry */
  282.                 continue;
  283.             }
  284.             if (d->name[0] == FAT_DENTRY_ERASED) {
  285.                 /* not-currently-used entry */
  286.                 continue;
  287.             }
  288.             if (d->name[0] == FAT_DENTRY_UNUSED) {
  289.                 /* never used entry */
  290.                 block_put(b);
  291.                 return NULL;
  292.             }
  293.             if (d->name[0] == FAT_DENTRY_DOT) {
  294.                 /*
  295.                  * Most likely '.' or '..'.
  296.                  * It cannot occur in a regular file name.
  297.                  */
  298.                 continue;
  299.             }
  300.        
  301.             dentry_name_canonify(d, name);
  302.             if (strcmp(name, component) == 0) {
  303.                 /* hit */
  304.                 void *node = fat_node_get(parentp->dev_handle,
  305.                     (fs_index_t)uint16_t_le2host(d->firstc),
  306.                     parentp->index);
  307.                 block_put(b);
  308.                 return node;
  309.             }
  310.         }
  311.         block_put(b);
  312.     }
  313.  
  314.     return NULL;
  315. }
  316.  
  317. static fs_index_t fat_index_get(void *node)
  318. {
  319.     fat_node_t *fnodep = (fat_node_t *)node;
  320.     if (!fnodep)
  321.         return 0;
  322.     return fnodep->index;
  323. }
  324.  
  325. static size_t fat_size_get(void *node)
  326. {
  327.     return ((fat_node_t *)node)->size;
  328. }
  329.  
  330. static unsigned fat_lnkcnt_get(void *node)
  331. {
  332.     return ((fat_node_t *)node)->lnkcnt;
  333. }
  334.  
  335. static void *fat_root_get(dev_handle_t dev_handle)
  336. {
  337.     return fat_node_get(dev_handle, 0, 0); 
  338. }
  339.  
  340. static char fat_plb_get_char(unsigned pos)
  341. {
  342.     return fat_reg.plb_ro[pos % PLB_SIZE];
  343. }
  344.  
  345. static bool fat_is_directory(void *node)
  346. {
  347.     return ((fat_node_t *)node)->type == FAT_DIRECTORY;
  348. }
  349.  
  350. static bool fat_is_file(void *node)
  351. {
  352.     return ((fat_node_t *)node)->type == FAT_FILE;
  353. }
  354.  
  355. /** libfs operations */
  356. libfs_ops_t fat_libfs_ops = {
  357.     .match = fat_match,
  358.     .node_get = fat_node_get,
  359.     .create = NULL,
  360.     .destroy = NULL,
  361.     .link = NULL,
  362.     .unlink = NULL,
  363.     .index_get = fat_index_get,
  364.     .size_get = fat_size_get,
  365.     .lnkcnt_get = fat_lnkcnt_get,
  366.     .has_children = NULL,
  367.     .root_get = fat_root_get,
  368.     .plb_get_char = fat_plb_get_char,
  369.     .is_directory = fat_is_directory,
  370.     .is_file = fat_is_file
  371. };
  372.  
  373. void fat_lookup(ipc_callid_t rid, ipc_call_t *request)
  374. {
  375.     libfs_lookup(&fat_libfs_ops, fat_reg.fs_handle, rid, request);
  376. }
  377.  
  378. /**
  379.  * @}
  380.  */
  381.