Subversion Repositories HelenOS

Rev

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