Subversion Repositories HelenOS

Rev

Rev 2859 | Rev 2864 | 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. #define FIN_KEY_DEV_HANDLE  0
  54. #define FIN_KEY_INDEX       1
  55.  
  56. /** Futex protecting both fin_hash and ffn_head. */
  57. futex_t fin_futex = FUTEX_INITIALIZER;
  58.  
  59. /** Hash table of FAT in-core nodes. */
  60. hash_table_t fin_hash;
  61.  
  62. /** List of free FAT in-core nodes. */
  63. link_t ffn_head;
  64.  
  65. #define FAT_NAME_LEN        8
  66. #define FAT_EXT_LEN     3
  67.  
  68. #define FAT_PAD         ' '
  69.  
  70. #define FAT_DENTRY_UNUSED   0x00
  71. #define FAT_DENTRY_E5_ESC   0x05
  72. #define FAT_DENTRY_DOT      0x2e
  73. #define FAT_DENTRY_ERASED   0xe5
  74.  
  75. static void dentry_name_canonify(fat_dentry_t *d, char *buf)
  76. {
  77.     int i;
  78.  
  79.     for (i = 0; i < FAT_NAME_LEN; i++) {
  80.         if (d->name[i] == FAT_PAD) {
  81.             buf++;
  82.             break;
  83.         }
  84.         if (d->name[i] == FAT_DENTRY_E5_ESC)
  85.             *buf++ = 0xe5;
  86.         else
  87.             *buf++ = d->name[i];
  88.     }
  89.     if (d->ext[0] != FAT_PAD)
  90.         *buf++ = '.';
  91.     for (i = 0; i < FAT_EXT_LEN; i++) {
  92.         if (d->ext[i] == FAT_PAD) {
  93.             *buf = '\0';
  94.             return;
  95.         }
  96.         if (d->ext[i] == FAT_DENTRY_E5_ESC)
  97.             *buf++ = 0xe5;
  98.         else
  99.             *buf++ = d->ext[i];
  100.     }
  101. }
  102.  
  103. /* TODO and also move somewhere else */
  104. typedef struct {
  105.     void *data;
  106. } block_t;
  107.  
  108. static block_t *block_get(dev_handle_t dev_handle, off_t offset)
  109. {
  110.     return NULL;    /* TODO */
  111. }
  112.  
  113. static void block_put(block_t *block)
  114. {
  115.     /* TODO */
  116. }
  117.  
  118.  
  119. #define FAT_BS(b)       ((fat_bs_t *)((b)->data))
  120.  
  121. #define FAT_CLST_FIRST  0x0002
  122. #define FAT_CLST_BAD    0xfff7
  123. #define FAT_CLST_LAST1  0xfff8
  124. #define FAT_CLST_LAST8  0xffff
  125.  
  126. /** Convert cluster number to an index within a FAT.
  127.  *
  128.  * Format Identifier and cluster numbering is considered.
  129.  */
  130. #define C2FAT_IDX(c)    (1 + (c) - FAT_CLST_FIRST)
  131.  
  132. static block_t *fat_block_get(dev_handle_t dev_handle, fs_index_t index,
  133.     off_t offset)
  134. {
  135.     block_t *bb;
  136.     block_t *b;
  137.     unsigned bps;
  138.     unsigned spc;
  139.     unsigned rscnt;     /* block address of the first FAT */
  140.     unsigned fatcnt;
  141.     unsigned rde;
  142.     unsigned rds;       /* root directory size */
  143.     unsigned sf;
  144.     unsigned ssa;       /* size of the system area */
  145.     unsigned clusters;
  146.     unsigned clst = index;
  147.     unsigned i;
  148.  
  149.     bb = block_get(dev_handle, BS_BLOCK);
  150.     bps = uint16_t_le2host(FAT_BS(bb)->bps);
  151.     spc = FAT_BS(bb)->spc;
  152.     rscnt = uint16_t_le2host(FAT_BS(bb)->rscnt);
  153.     fatcnt = FAT_BS(bb)->fatcnt;
  154.     rde = uint16_t_le2host(FAT_BS(bb)->root_ent_max);
  155.     sf = uint16_t_le2host(FAT_BS(bb)->sec_per_fat);
  156.     block_put(bb);
  157.  
  158.     rds = (sizeof(fat_dentry_t) * rde) / bps;
  159.     rds += ((sizeof(fat_dentry_t) * rde) % bps != 0);
  160.     ssa = rscnt + fatcnt * sf + rds;
  161.  
  162.     if (!index) {
  163.         /* root directory special case */
  164.         assert(offset < rds);
  165.         b = block_get(dev_handle, rscnt + fatcnt * sf + offset);
  166.         return b;
  167.     }
  168.  
  169.     clusters = offset / spc;
  170.     for (i = 0; i < clusters; i++) {
  171.         unsigned fsec;  /* sector offset relative to FAT1 */
  172.         unsigned fidx;  /* FAT1 entry index */
  173.  
  174.         assert(clst >= FAT_CLST_FIRST && clst < FAT_CLST_BAD);
  175.         fsec = (C2FAT_IDX(clst) * sizeof(uint16_t)) / bps;
  176.         fidx = C2FAT_IDX(clst) % (bps / sizeof(uint16_t));
  177.         /* read FAT1 */
  178.         b = block_get(dev_handle, rscnt + fsec);
  179.         clst = uint16_t_le2host(((uint16_t *)b->data)[fidx]);
  180.         assert(clst != FAT_CLST_BAD);
  181.         assert(clst < FAT_CLST_LAST1);
  182.         block_put(b);
  183.     }
  184.  
  185.     b = block_get(dev_handle, ssa + (clst - FAT_CLST_FIRST) * spc +
  186.         offset % spc);
  187.  
  188.     return b;
  189. }
  190.  
  191. static void fat_node_initialize(fat_node_t *node)
  192. {
  193.     futex_initialize(&node->lock, 1);
  194.     node->type = 0;
  195.     node->index = 0;
  196.     node->pindex = 0;
  197.     node->dev_handle = 0;
  198.     link_initialize(&node->fin_link);
  199.     link_initialize(&node->ffn_link);
  200.     node->size = 0;
  201.     node->lnkcnt = 0;
  202.     node->refcnt = 0;
  203.     node->dirty = false;
  204. }
  205.  
  206. static uint16_t fat_bps_get(dev_handle_t dev_handle)
  207. {
  208.     block_t *bb;
  209.     uint16_t bps;
  210.    
  211.     bb = block_get(dev_handle, BS_BLOCK);
  212.     assert(bb != NULL);
  213.     bps = uint16_t_le2host(FAT_BS(bb)->bps);
  214.     block_put(bb);
  215.  
  216.     return bps;
  217. }
  218.  
  219. typedef enum {
  220.     FAT_DENTRY_SKIP,
  221.     FAT_DENTRY_LAST,
  222.     FAT_DENTRY_VALID
  223. } fat_dentry_clsf_t;
  224.  
  225. static fat_dentry_clsf_t fat_classify_dentry(fat_dentry_t *d)
  226. {
  227.     if (d->attr & FAT_ATTR_VOLLABEL) {
  228.         /* volume label entry */
  229.         return FAT_DENTRY_SKIP;
  230.     }
  231.     if (d->name[0] == FAT_DENTRY_ERASED) {
  232.         /* not-currently-used entry */
  233.         return FAT_DENTRY_SKIP;
  234.     }
  235.     if (d->name[0] == FAT_DENTRY_UNUSED) {
  236.         /* never used entry */
  237.         return FAT_DENTRY_LAST;
  238.     }
  239.     if (d->name[0] == FAT_DENTRY_DOT) {
  240.         /*
  241.          * Most likely '.' or '..'.
  242.          * It cannot occur in a regular file name.
  243.          */
  244.         return FAT_DENTRY_SKIP;
  245.     }
  246.     return FAT_DENTRY_VALID;
  247. }
  248.  
  249. static void fat_sync_node(fat_node_t *node)
  250. {
  251.     /* TODO */
  252. }
  253.  
  254. /** Instantiate a FAT in-core node. */
  255. static void *
  256. fat_node_get(dev_handle_t dev_handle, fs_index_t index)
  257. {
  258.     return NULL;    /* TODO */
  259. }
  260.  
  261. static void fat_node_put(void *node)
  262. {
  263.     /* TODO */
  264. }
  265.  
  266. static void *fat_create(int flags)
  267. {
  268.     return NULL;    /* not supported at the moment */
  269. }
  270.  
  271. static int fat_destroy(void *node)
  272. {
  273.     return ENOTSUP; /* not supported at the moment */
  274. }
  275.  
  276. static bool fat_link(void *prnt, void *chld, const char *name)
  277. {
  278.     return false;   /* not supported at the moment */
  279. }
  280.  
  281. static int fat_unlink(void *prnt, void *chld)
  282. {
  283.     return ENOTSUP; /* not supported at the moment */
  284. }
  285.  
  286. static void *fat_match(void *prnt, const char *component)
  287. {
  288.     fat_node_t *parentp = (fat_node_t *)prnt;
  289.     char name[FAT_NAME_LEN + 1 + FAT_EXT_LEN + 1];
  290.     unsigned i, j;
  291.     unsigned bps;       /* bytes per sector */
  292.     unsigned dps;       /* dentries per sector */
  293.     unsigned blocks;
  294.     fat_dentry_t *d;
  295.     block_t *b;
  296.  
  297.     bps = fat_bps_get(parentp->dev_handle);
  298.     dps = bps / sizeof(fat_dentry_t);
  299.     blocks = parentp->size / bps + (parentp->size % bps != 0);
  300.     for (i = 0; i < blocks; i++) {
  301.         unsigned dentries;
  302.        
  303.         b = fat_block_get(parentp->dev_handle, parentp->index, i);
  304.         dentries = (i == blocks - 1) ?
  305.             parentp->size % sizeof(fat_dentry_t) :
  306.             dps;
  307.         for (j = 0; j < dentries; j++) {
  308.             d = ((fat_dentry_t *)b->data) + j;
  309.             switch (fat_classify_dentry(d)) {
  310.             case FAT_DENTRY_SKIP:
  311.                 continue;
  312.             case FAT_DENTRY_LAST:
  313.                 block_put(b);
  314.                 return NULL;
  315.             default:
  316.             case FAT_DENTRY_VALID:
  317.                 dentry_name_canonify(d, name);
  318.                 break;
  319.             }
  320.             if (strcmp(name, component) == 0) {
  321.                 /* hit */
  322.                 void *node = fat_node_get(parentp->dev_handle,
  323.                     (fs_index_t)uint16_t_le2host(d->firstc));
  324.                 block_put(b);
  325.                 return node;
  326.             }
  327.         }
  328.         block_put(b);
  329.     }
  330.  
  331.     return NULL;
  332. }
  333.  
  334. static fs_index_t fat_index_get(void *node)
  335. {
  336.     fat_node_t *fnodep = (fat_node_t *)node;
  337.     if (!fnodep)
  338.         return 0;
  339.     return fnodep->index;
  340. }
  341.  
  342. static size_t fat_size_get(void *node)
  343. {
  344.     return ((fat_node_t *)node)->size;
  345. }
  346.  
  347. static unsigned fat_lnkcnt_get(void *node)
  348. {
  349.     return ((fat_node_t *)node)->lnkcnt;
  350. }
  351.  
  352. static bool fat_has_children(void *node)
  353. {
  354.     fat_node_t *nodep = (fat_node_t *)node;
  355.     unsigned bps;
  356.     unsigned dps;
  357.     unsigned blocks;
  358.     block_t *b;
  359.     unsigned i, j;
  360.  
  361.     if (nodep->type != FAT_DIRECTORY)
  362.         return false;
  363.  
  364.     bps = fat_bps_get(nodep->dev_handle);
  365.     dps = bps / sizeof(fat_dentry_t);
  366.  
  367.     blocks = nodep->size / bps + (nodep->size % bps != 0);
  368.  
  369.     for (i = 0; i < blocks; i++) {
  370.         unsigned dentries;
  371.         fat_dentry_t *d;
  372.    
  373.         b = fat_block_get(nodep->dev_handle, nodep->index, i);
  374.         dentries = (i == blocks - 1) ?
  375.             nodep->size % sizeof(fat_dentry_t) :
  376.             dps;
  377.         for (j = 0; j < dentries; j++) {
  378.             d = ((fat_dentry_t *)b->data) + j;
  379.             switch (fat_classify_dentry(d)) {
  380.             case FAT_DENTRY_SKIP:
  381.                 continue;
  382.             case FAT_DENTRY_LAST:
  383.                 block_put(b);
  384.                 return false;
  385.             default:
  386.             case FAT_DENTRY_VALID:
  387.                 block_put(b);
  388.                 return true;
  389.             }
  390.             block_put(b);
  391.             return true;
  392.         }
  393.         block_put(b);
  394.     }
  395.  
  396.     return false;
  397. }
  398.  
  399. static void *fat_root_get(dev_handle_t dev_handle)
  400. {
  401.     return fat_node_get(dev_handle, 0);
  402. }
  403.  
  404. static char fat_plb_get_char(unsigned pos)
  405. {
  406.     return fat_reg.plb_ro[pos % PLB_SIZE];
  407. }
  408.  
  409. static bool fat_is_directory(void *node)
  410. {
  411.     return ((fat_node_t *)node)->type == FAT_DIRECTORY;
  412. }
  413.  
  414. static bool fat_is_file(void *node)
  415. {
  416.     return ((fat_node_t *)node)->type == FAT_FILE;
  417. }
  418.  
  419. /** libfs operations */
  420. libfs_ops_t fat_libfs_ops = {
  421.     .match = fat_match,
  422.     .node_get = fat_node_get,
  423.     .node_put = fat_node_put,
  424.     .create = fat_create,
  425.     .destroy = fat_destroy,
  426.     .link = fat_link,
  427.     .unlink = fat_unlink,
  428.     .index_get = fat_index_get,
  429.     .size_get = fat_size_get,
  430.     .lnkcnt_get = fat_lnkcnt_get,
  431.     .has_children = fat_has_children,
  432.     .root_get = fat_root_get,
  433.     .plb_get_char = fat_plb_get_char,
  434.     .is_directory = fat_is_directory,
  435.     .is_file = fat_is_file
  436. };
  437.  
  438. void fat_lookup(ipc_callid_t rid, ipc_call_t *request)
  439. {
  440.     libfs_lookup(&fat_libfs_ops, fat_reg.fs_handle, rid, request);
  441. }
  442.  
  443. /**
  444.  * @}
  445.  */
  446.